﻿using AiMoBridge.Interface;
using AiMoBridge.Interface.Client;
using AiMoBridge.Paths;
using AiMoWindows.Compiler;
using AiMoWindows.MainActions;
using AiMoWindows.MainActions.LibraryActions.ExampleItems;
using AiMoWindows.MainActions.Mode;
using AiMoWindows.MainActions.SecondaryActions;
using AiMoWindows.Server;
using AiMoWindows.Windows;
using System.Drawing;
using System.IO;
using System.Windows;

namespace AiMoWindows.Entrance
{

    class AiMoProgram : IAppEntrance
    {
        static AiMoProgram? _Instance;
        public static AiMoProgram Instance => _Instance ?? throw new Exception("Debug: AiMoProgram Instance cannot be null");
        public ExecuterMode AiMoExecuterMode { get; }
        /// <summary>
        /// 如果 ExecuterMode 是 ExecuterMode.Grasshopper，将会附带一个GH文件，空则为""
        /// </summary>
        public string ScriptFileFromGH { get; }
        public AiMoProgram(ExecuterMode openMode, string ghPassedFilePath)
        {
            _Instance = this;
            AiMoExecuterMode = openMode;
            ScriptFileFromGH = ghPassedFilePath;
        }

        IExecutor? executer = null;
        IBridgeInfo? bridgeInfo = null;

        bool inited = false;
        bool IAppEntrance.Init(IExecutor appExecutor, IBridgeInfo bridgeInfo, out string error)
        {
            if (appExecutor != null && bridgeInfo != null)
            {
                this.bridgeInfo = bridgeInfo;
                executer = appExecutor;
                ServerHelper.SetRhinoVersion(bridgeInfo.CurrentRhinoVersion);
                try
                {
                    ReferenceAssemblis.SetExternalAssemblyLocations(bridgeInfo.RhinoAssemblyLocations);
                }
                catch (Exception ex)
                {
                    throw new Exception($"Cannot load external assemblies:\r\n    {string.Join("\r\n    ", bridgeInfo.RhinoAssemblyLocations)}\r\n{ex.Message}");
                }
                inited = true;
                error = "";
                return true;
            }
            error = (appExecutor == null) ? "appExecutor is null" : "";
            error += (bridgeInfo == null) ? "bridgeInfo is null" : "";
            return false;
        }
        bool IAppEntrance.Init(string startupPath, out string error)
        {
            DirectoryInfo startUpDirectory = new DirectoryInfo(startupPath);
            if (startUpDirectory.Exists)
            {
                if (startUpDirectory.Parent == null || !startUpDirectory.Parent.Exists)
                {
                    error = "Cannot get parent directory from startup path: " + startupPath;
                    return false;
                }
                ServerHelper.SetRhinoVersion("6.25.20114.5271");
                string[] locations = new string[]
                {
                    Path.Combine(startupPath, "RhinoCommon.dll"),
                    Path.Combine(startupPath, "AiMoWindows.dll"),
                    Path.Combine(startUpDirectory.Parent.FullName, "AiMo3D.rhp")
                };
                ReferenceAssemblis.SetExternalAssemblyLocations(locations);
                foreach (string location in locations)
                {
                    if (!File.Exists(location))
                    {
                        error = $"{location} is not existed";
                        return false;
                    }
                }
                inited = true;
                error = "";
                return true;
            }
            error = "startupPath is not existed";
            return false;
        }

        bool IAppEntrance.Start(string filePath, bool autoLogin, out string error)
        {
            if (!inited)
            {
                error = "Debug: Program is not inited";
                return false;
            }
            ExternalSettings.Load();
            var size = ExternalSettings.EditorFontSize;
            if (string.IsNullOrEmpty(filePath))
            {
                if (!OpenNewAimoScriptForm(withDefaultExample: true, out error)) return false;
            }
            else
            {
                if (!OpenNewAimoScriptForm(filePath, out error)) return false;
            }
            new Thread(() =>
            {
                PathManager.ClearCaches();
            }).Start();

            if (autoLogin) new Thread(AutoLogin).Start();
            return true;
        }

        void AutoLogin()
        {
            bool re = LoginController.AutoLogin();
            if (re) UpdateAllWindowState();
        }
        internal Bitmap? TakeScreenShot => bridgeInfo?.GetScreenShot(new System.Drawing.Size(800, 800)) ?? null;

        #region Create Forms

        Windows.CommandLibrary.CommandLibraryWindow? m_CommandsLibraryWindow;
        public void OpenOrShowCommandLibraryWindow()
        {
            Application.Current.Dispatcher.InvokeAsync(() =>
            {
                if (m_CommandsLibraryWindow == null || ((IAiMoWindow)m_CommandsLibraryWindow).CloseActived)
                {
                    LibraryExamples.CreateInitialExamples();
                    m_CommandsLibraryWindow = new Windows.CommandLibrary.CommandLibraryWindow(executer);
                    WindowStarter.ShowInRandomLocation(m_CommandsLibraryWindow);
                    aimoWindows.Add(m_CommandsLibraryWindow);
                }
                else
                {
                    m_CommandsLibraryWindow?.Activate();
                }
            });
        }
        // 直接启动AiMo
        public bool OpenNewAimoScriptForm(bool withDefaultExample, out string error)
        {
            bool re = false;
            string error0 = "";
            Application.Current.Dispatcher.InvokeAsync(() =>
            {
                try
                {
                    // 通过AiMo命令，没有Path，打开带案例的Aimo
                    IAiMoWindow window = WindowStarter.OpenNewScriptWindow(executer, !withDefaultExample);
                    aimoWindows.Add(window);
                    ICheckUpdateClient checkUpdateClient = GetClient.GetCheckUpdateClient();
                    checkUpdateClient.UpdateEvent += Update;
                    checkUpdateClient.CheckUpdate();
                    re = true;
                }
                catch (Exception ex)
                {
                    error0 = ex.FormatException();
                }
            }).Wait();
            error = error0;
            return re;
        }
        /// <summary>
        /// 从已有文件，打开一个代码编辑器
        /// </summary>
        public bool OpenNewAimoScriptForm(string filePath, out string error)
        {
            if (string.IsNullOrEmpty(filePath))
            {
                return OpenNewAimoScriptForm(withDefaultExample: false, out error);
            }
            bool re = false;
            string error0 = "";
            Application.Current.Dispatcher.InvokeAsync(() =>
            {
                try
                {
                    IAiMoWindow window = WindowStarter.OpenNewScriptWindow(executer, filePath);
                    aimoWindows.Add(window);
                    ICheckUpdateClient checkUpdateClient = GetClient.GetCheckUpdateClient();
                    checkUpdateClient.UpdateEvent += Update;
                    checkUpdateClient.CheckUpdate();
                    re = true;
                }
                catch (Exception ex)
                {
                    error0 = ex.FormatException();
                }
            }).Wait();
            error = error0;
            return re;
        }

        public void Update(ClientEventArgs e)
        {
            ServerHelper.SetInfoFromServer(e.LatestAiMoVersion, e.NotificationFromServer);
            UpdateAllWindowState();
        }

        public bool OpenNewAimoScriptForm(IScriptMessage message, out string error)
        {
            bool re = false;
            string error0 = "";
            Application.Current.Dispatcher.InvokeAsync(() =>
            {
                try
                {
                    IAiMoWindow window = WindowStarter.OpenNewScriptWindow(executer, message);
                    aimoWindows.Add(window);
                    re = true;
                }
                catch (Exception ex)
                {
                    error0 = ex.FormatException();
                }
            }).Wait();
            error = error0;
            return re;
        }
        public bool OpenNewAimoScriptForm(ScriptDownloadResult downloadResult, out string error)
        {
            try
            {
                error = "";
                IAiMoWindow window = WindowStarter.OpenNewScriptWindow(executer, downloadResult);
                aimoWindows.Add(window);
                return true;
            }
            catch (Exception ex)
            {
                error = ex.FormatException();
                return false;
            }

        }

        /// <summary>
        /// 打开一个AI对话Form
        /// </summary>
        public void OpenNewAiMoAiWindow()
        {
            Application.Current.Dispatcher.InvokeAsync(() =>
            {
                Windows.AiAssistant.AiAssistantWindow aiAssistantWindow = new Windows.AiAssistant.AiAssistantWindow();
                WindowStarter.ShowInRandomLocation(aiAssistantWindow);
                aiAssistantWindow.Init();
                aimoWindows.Add(aiAssistantWindow);
            });
        }

        #endregion

        #region All windows state control
        /// <summary>
        /// 更新所有Windows的语言和登录登出状态
        /// </summary>
        public void UpdateAllWindowState()
        {
            foreach (IAiMoWindow window in aimoWindows.ToArray())
            {
                if (window.CloseActived)
                {
                    aimoWindows.Remove(window);
                    continue;
                }
                window.UpdateState();
            }
        }


        readonly List<IAiMoWindow> aimoWindows = new List<IAiMoWindow>();

        public bool GetLastScriptWindowsBounds(out Rect bounds)
        {
            bounds = Rect.Empty;
            foreach (IAiMoWindow window in aimoWindows.ToArray())
            {
                if (!window.CloseActived)
                {
                    if (window is Windows.Scripts.ScriptWindow scriptWindow)
                    {
                        bounds = scriptWindow.RestoreBounds;

                    }
                }
            }
            return !bounds.IsEmpty;
        }

        #endregion
    }
}
